home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / FWiX / FWiXDriver / FWiXDriver.c next >
Encoding:
Text File  |  1999-04-12  |  65.5 KB  |  2,139 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXDriver.c
  3.  
  4.     Contains:    Driver software for FireWire File Exchange.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (jkl)    Jay Lloyd
  23.  
  24.     Change History (most recent first):
  25.  
  26.       <FW29>      7/7/98    jkl        Deallocate node's data buffer address space when closing node.
  27.         <28>     1/15/98    jkl        Update for new headers.
  28.         <27>     5/28/97    jkl        Added a check for control packet index equal to 1 for a node
  29.                                     being restarted. Cleaned up some of the inUse and timing checks
  30.                                     added in last revision to investigate 5+ node problem.
  31.       <FW26>     5/27/97    jkl        Added a control packet indexing function to make sure control
  32.                                     packets are handled only once. Changed the flow control timer to
  33.                                     send flow control requests until a reply is received. This would
  34.                                     fix a case where a flow control request never got a reply.
  35.                                     Added more error checking and in use checking to investigate 5+
  36.                                     node problem.
  37.       <FW25>     5/15/97    jkl        Added a checksum routine around send data and data done. Added
  38.                                     an index to the flow control messages to only handle a reply
  39.                                     from the latest request. Put a check around sendpacket to make
  40.                                     sure it is not reentered.
  41.       <FW24>     2/27/97    jkl        Modified the WriteDataComplete routine to turn off flow control.
  42.                                     This will cause a flow control request and reply to be sent to
  43.                                     ensure the receive data buffer does not get overwritten with
  44.                                     more data before the receiver reads the existing data out of the
  45.                                     buffer. Reduced flow control retry time from 100 to 10 ms to
  46.                                     reduce transfer stalls.
  47.       <FW23>     2/21/97    ES        Added in use flags for all FWCommandObjects. Changed FWXClose to
  48.                                     wait for all of these flags to clear before doing any closing
  49.                                     activity. Removed wait on writePending. This fixes a hang on
  50.                                     closing bug.
  51.       <FW22>     2/21/97    EA        Added option to send diagnostic messages to FireBug.
  52.       <FW21>     2/21/97    jkl        Modified data transmissions to be sent to non-notify address
  53.                                     space.
  54.       <FW20>     2/20/97    ES        Changed FWClientAsynchRequestParams buffer field to
  55.                                     receiveBuffer.
  56.       <FW19>     2/19/97    jkl        Added a flow control send pending flag to make sure two messages
  57.                                     do not get sent at one time. Moved available buffer counts from
  58.                                     write completion routine to write routine.
  59.       <FW18>     2/14/97    jkl        Changed the flow control mechanism so the sender has to request
  60.                                     from the receiver how many packets he can send.
  61.       <FW17>     2/13/97    jkl        Added FlowControl packet counter to make sure flow control is
  62.                                     started properly.
  63.       <FW16>     2/13/97    jkl        Changed flow control to just keep up with number of data packets
  64.                                     available and sent. The flow control message is only sent when
  65.                                     all of the read packets have been received and are available,
  66.                                     thus the sender will stall after each number of sends. Changed
  67.                                     write notify routine to complete read data transaction when
  68.                                     requested data is equal to received data.
  69.       <FW15>     2/11/97    ES        Added closed boolean to FWXNodeData record. Added checks for
  70.                                     node being closed to prevent any writes going out or being
  71.                                     processed when we're closing a node connection. Changed write
  72.                                     queue deallocation to wait until no more writes are pending
  73.                                     before deallocating queue.
  74.       <FW14>     2/11/97    jkl        Added support for read control and data queues. Changed flow
  75.                                     control to a you can send me this much mechanism. Moved
  76.                                     FWXCommandComplete routine to the family.
  77.       <FW13>      2/2/97    jkl        Modified flow control time delay to check more often if it is ok
  78.                                     to write and write routine to handle writing buffers larger than
  79.                                     the allocated firewire buffer size.
  80.       <FW12>     1/27/97    ES        Changed FWXWrite to make sure there is still an item on the
  81.                                     write queue before processing the head of the queue (a race
  82.                                     condition was happening here). Changed FWXCloseNode to check if
  83.                                     the read and write queues were non-nil before deallocating.
  84.       <FW11>     1/16/97    ES        Changed FWXCreatePDriverUnitDirectory to set CSRROMEntryID's to
  85.                                     invalid before using them. Also, added code to deallocate entry
  86.                                     ID's.
  87.       <FW10>     1/16/97    jkl        Cleaned up read/write buffers on close.
  88.        <FW9>      1/8/97    ES        Changed to a FireWire protocol driver. Removed fixed FireWire
  89.                                     address allocation.
  90.        <FW8>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s.
  91.        <FW7>    12/16/96    ES        Changed to work with new read/write/lock request/complete
  92.                                     processing mechanism.
  93.        <FW6>     12/3/96    ES        Added kFWFixedAddress flag to FWAllocateAddressSpace.
  94.        <FW5>    11/13/96    jkl        Moved from DoDriverIO interface back to CallDriver. Added
  95.                                     multiple machine support. Added packet receive buffering.
  96.        <FW4>     10/31/96    jkl        Added flow control constants.
  97.        <FW3>     10/13/96    jkl        Added a basic flow control capability to turn off transmission
  98.                                        when the number of received buffers is low. All queue routines
  99.                                     are now the dsl queue routines. The ioMisc field in a parameter
  100.                                     block is now used to identify the packet type. For control
  101.                                     packets, the packet type is still also in the first long word
  102.                                     of the buffer. A sendpacket routine is now called by the write
  103.                                     handler and the write completion handler to send a packet. Fork
  104.                                     data is sent to a separate address space that is now set to write
  105.                                     notify.
  106.        <FW2>     10/3/96    jkl        Changed to use set driver interface calls rather than driver
  107.                                     interface table.
  108.        <FW1>     10/2/96    jkl        initial check-in, copied from avt driver
  109.                                        Added DoDriverIO interface.
  110.  
  111. */
  112.  
  113. #include <Types.h>
  114. #include <Errors.h>
  115. #include <Devices.h>
  116. #include <DriverServices.h>
  117. #include <FireWire.h>
  118.  
  119. #include "FWiX.h"
  120. #include "FWiXDriver.h"
  121.  
  122. #include <stdio.h>
  123. char  debugStr[256];
  124. static pascal void FWDebugStr(
  125.     ConstStr255Param            debuggerMsg)
  126. {
  127. #ifdef FW_DEBUG_BUILD
  128. #if FW_DEBUG_BUILD
  129.     DebugStr (debuggerMsg);
  130. #endif
  131. #endif
  132. }
  133.  
  134.  
  135. // define FireBug to enable sending diagnostic messages to FireBug on the fly.
  136. // WARNING:  Read the notes below first.  Be sure use "tcode on 1" in FireBug
  137. // so that you can see the messages.  [Also use "ack 0" if you don't want to
  138. // see many other packets]
  139.  
  140. //#define FireBug
  141. #ifdef FireBug
  142. static char fireBug[256];
  143. static FWReferenceID fireBugID;
  144. static FWCommandObjectID fireBugCommandObjectID;
  145. static UInt32 fireBugNeedCommandObject = 1;
  146.  
  147. static void FireBugMsg (char * msg)
  148. {
  149.     FWTopologyMap topology;
  150.     OSStatus status;
  151.     
  152.     if (fireBugNeedCommandObject) return;
  153.     
  154.     // It would probably be more safe to add a mechanism to make sure the
  155.     // most recent FireBugMsg completed before we recycle the command object.
  156.     // But I expect that the FWGetTopologyMap will probably take care of this.
  157.     
  158.     status = FWGetTopologyMap (fireBugID, &topology);
  159.     status = FWSetAsynchCommandGeneration (fireBugCommandObjectID, topology.generationNumber);
  160.     status = FWSetAsynchCommandBuffer (fireBugCommandObjectID, msg);
  161.     status = FWSetAsynchCommandLength (fireBugCommandObjectID, strlen (msg) + 1);
  162.     status = FWWrite (fireBugCommandObjectID);
  163. }
  164.  
  165. static void FireBugPrep (FWReferenceID tempID)
  166. {
  167.     OSStatus status;
  168.     
  169.     if (fireBugNeedCommandObject)
  170.     {
  171.         status = FWAllocateAsynchCommandObject (&fireBugCommandObjectID);
  172.         if (status == noErr)
  173.         {            
  174.             FWGetLocalFWReferenceIDFromFWReferenceID (tempID, &fireBugID);
  175.  
  176.             FWSetFWCommandParams(fireBugCommandObjectID, fireBugID, 0, nil, 0);
  177.             FWSetCommonAsynchCommandParams (fireBugCommandObjectID,
  178.                                             0x42420000, 0x00000000,
  179.                                             (Ptr) fireBug, sizeof (fireBug));
  180.             FWSetAsynchCommandMaxRetries (fireBugCommandObjectID, 0);
  181.             FWSetAsynchCommandMaxPayloadSize (fireBugCommandObjectID, 512);
  182.             FWSetAsynchCommandTransferFlags (fireBugCommandObjectID,
  183.                                              kFWAsynchAbsoluteAddress |
  184.                                              kFWAsynchOverrideMaxPayload);
  185.         }
  186.     
  187.         fireBugNeedCommandObject = 0;
  188.     }
  189. }
  190. #endif
  191.  
  192.  
  193. ////////////////////////////////////////////////////////////////////////////////
  194. //
  195. // Internal procedure prototypes.
  196. //
  197.  
  198. static void HandleFlowControlNotify (
  199.     FWXNodeDataPtr                pFWXNodeData,
  200.     Ptr                            pMessage);
  201.  
  202. static void HandleControlNotify (
  203.     FWXNodeDataPtr                pFWXNodeData,
  204.     Ptr                            pMessage,
  205.     UInt32                        msgLength);
  206.  
  207. static void HandleDataDone (
  208.     FWXNodeDataPtr                pFWXNodeData,
  209.     UInt32                        count,
  210.     UInt32                        checkSum);
  211.  
  212. static OSStatus    FWPDriverUnitAdded (
  213.     FWPDriverID                    fwPDriverID,
  214.     UInt32                        fwPDriverSpecificData,
  215.     FWUnitID                    fwUnitID);
  216.  
  217. static OSStatus    FWPDriverUnitRemoved (
  218.     FWPDriverID                    fwPDriverID,
  219.     UInt32                        fwPDriverSpecificData,
  220.     FWUnitID                    fwUnitID);
  221.  
  222. static void FlowControlComplete (
  223.     FWCommandObjectID            fwCommandObjectID,
  224.     OSStatus                    commandStatus,
  225.     UInt32                        completionProcData);
  226.  
  227. static void FlowControlReplyComplete (
  228.     FWCommandObjectID            fwCommandObjectID,
  229.     OSStatus                    commandStatus,
  230.     UInt32                        completionProcData);
  231.  
  232. static OSStatus FWXRead (
  233.     FWXAsynchParamsPtr            pFWXAsynchParams);
  234.  
  235. static OSStatus FWXWrite (
  236.     FWXAsynchParamsPtr            pFWXAsynchParams);
  237.  
  238. static void DataDoneComplete(
  239.     FWCommandObjectID            fwCommandObjectID,
  240.     OSStatus                    commandStatus,
  241.     UInt32                        completionProcData);
  242.  
  243. static void HandleWriteDataComplete(
  244.     FWCommandObjectID            fwCommandObjectID,
  245.     FWXNodeDataPtr                pFWXNodeData,
  246.     IOParamPtr                    pCompleteIOPb);
  247.  
  248. static void HandleWriteControlComplete(
  249.     FWCommandObjectID            fwCommandObjectID,
  250.     FWXNodeDataPtr                pFWXNodeData,
  251.     IOParamPtr                    pCompleteIOPb);
  252.  
  253. static void FWXWriteCompletion (
  254.     FWCommandObjectID            fwCommandObjectID,
  255.     OSStatus                    commandStatus,
  256.     UInt32                        completionProcData);
  257.  
  258. static OSStatus RetryFlowControl (
  259.     void                        *p1,
  260.     void                        *p2);
  261.  
  262. static OSStatus SendDataPacket(
  263.     FWXNodeDataPtr                pFWXNodeData,
  264.     IOParamPtr                    pb,
  265.     UInt32                        length);
  266.  
  267. static OSStatus SendControlPacket(
  268.     FWXNodeDataPtr                pFWXNodeData,
  269.     IOParamPtr                    pb,
  270.     UInt32                        length);
  271.  
  272. static OSStatus SendPacket (
  273.     FWXNodeDataPtr                pNodeData);
  274.     
  275. static OSStatus    FWXInitialize (
  276.     FWXInitializeParamsPtr        pFWXInitializeParams);
  277.  
  278. static OSStatus    FWXCreatePDriverUnitDirectory (
  279.     FWXDriverDataPtr            pFWXDriverData,
  280.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID);
  281.  
  282. static OSStatus    FWXTerminate (
  283.     FWXTerminateParamsPtr        pFWXTerminateParams);
  284.  
  285. static OSStatus FWXOpenNode (
  286.     FWXOpenNodeParamsPtr        pFWXInitializeParams);
  287.  
  288. static OSStatus FWXCloseNode (
  289.     FWXNodeDataPtr                pFWXNodeData);
  290.  
  291. static OSStatus SetupIOQueues (
  292.     FWXNodeDataPtr                pFWXNodeData);
  293.  
  294. static OSStatus FWXGetNodeDataFromNodeID (
  295.     FWXDriverDataPtr            pFWXDriverData,
  296.     UInt32                        generation,
  297.     UInt32                        nodeID,
  298.     FWXNodeDataPtr                *ppFWXNodeData);
  299.  
  300. ////////////////////////////////////////////////////////////////////////////////
  301. //
  302. // The driver descriptor.
  303. //
  304.  
  305. DriverDescription                 TheDriverDescription =
  306. {
  307.     kTheDescriptionSignature,
  308.     kInitialDriverDescriptor,
  309.     {
  310.         "\pFWiX",
  311.         1, 0, developStage, 1,
  312.     },
  313.     {
  314.         0                                        // driver runtime options
  315.         | (0 * kDriverIsLoadedUponDiscovery)
  316.         | (0 * kDriverIsOpenedUponLoad)
  317.         | (1 * kDriverIsUnderExpertControl)
  318.         | (1 * kDriverIsConcurrent)
  319.         | (1 * kDriverQueuesIOPB),
  320.         "\pFWiXDriver",
  321.     },
  322.  
  323.     1,
  324.     kServiceCategoryFWiX,
  325.     0,
  326.     1,0,0,0
  327. };
  328.     
  329. FWPDriverDescription            ThePDriverDescription =
  330. {
  331.     kTheFWPDriverDescriptionSignature,
  332.     kInitialFWPDriverDescriptor,
  333.  
  334.     kServiceCategoryFWDriver,
  335.     0,0,developStage,0,
  336.  
  337.     0,
  338.     "\pFWiX"
  339. };
  340.  
  341. ////////////////////////////////////////////////////////////////////////////////
  342. //
  343. //    FWClientWriteRequestInterface
  344. //
  345. //    Handle writes to the client. Check the type of received data by address
  346. //    space id. Set flow control information. If the data is control information
  347. //    send any file data information to the application then send the control
  348. //    information. If the data is file data add it to the receive buffer, if it
  349. //    overflows the receive buffer, send the buffer to the app and get a new one.
  350. //
  351.  
  352. OSStatus FWClientWriteCompleteInterface(
  353.     FWClientAsynchRequestParamsPtr
  354.                                 pFWClientAsynchRequestParams,
  355.     UInt32                        *pCommandAcceptance)
  356. {
  357.     FWXDriverDataPtr            pFWXDriverData;
  358.     FWXNodeDataPtr                pFWXNodeData;
  359.     OSStatus                    status = noErr;
  360.  
  361.     // recover our node data
  362.     //zzz check status
  363.     pFWXDriverData = (FWXDriverDataPtr) pFWClientAsynchRequestParams->pAddressSpecificData;
  364.     status = FWXGetNodeDataFromNodeID (pFWXDriverData,
  365.                                        pFWClientAsynchRequestParams->generation,
  366.                                        pFWClientAsynchRequestParams->sourceID,
  367.                                        &pFWXNodeData);
  368.  
  369.     if (status == noErr)
  370.     {
  371.         if (pFWClientAsynchRequestParams->fwAddressSpaceID == pFWXDriverData->fcAddressSpaceID)
  372.             
  373.             HandleFlowControlNotify (pFWXNodeData,
  374.                                      pFWClientAsynchRequestParams->receiveBuffer);
  375.                                      
  376.         else if (pFWClientAsynchRequestParams->fwAddressSpaceID == pFWXDriverData->controlAddressSpaceID)
  377.             
  378.             HandleControlNotify (pFWXNodeData,
  379.                                  pFWClientAsynchRequestParams->receiveBuffer,
  380.                                  pFWClientAsynchRequestParams->length);
  381.     }
  382.  
  383.     // Complete FireWire client command.
  384.     FWClientCommandIsComplete
  385.         (pFWClientAsynchRequestParams->fwClientInterfaceParams.fwClientCommandID,
  386.          status);
  387.  
  388.     // Return command acceptance.
  389.     //zzz is this the right way?  If we've completed the command, we can accept more.
  390.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  391.  
  392.     return status;
  393. }
  394.  
  395. ////////////////////////////////////////////////////////////////////////////////
  396. //
  397. // HandleFlowControlNotify
  398. //
  399. //    Handle notification of a flow control message received. If the message
  400. //    is a request, reply with the appropriate flow control value. If the
  401. //    message is a reply and there are now receive buffers available, try
  402. //    sending a packet. If there are no buffers available start a timer to
  403. //    wait and then send another flow control request.
  404. //
  405.  
  406. static void HandleFlowControlNotify (
  407.     FWXNodeDataPtr            pFWXNodeData,
  408.     Ptr                        pMessage)
  409. {
  410.     UInt32                    fcPacketCount;
  411.     UInt32                    messageType;
  412.     AbsoluteTime            fcRequestDelay;
  413.     OSStatus                status = noErr;
  414.     
  415.     messageType = ((UInt32 *) pMessage)[0];
  416.     switch (messageType)
  417.     {
  418.         case kFCDataRequest:
  419.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  420.             {
  421.                 pFWXNodeData->fcReplyBuffer[0] = kFCDataReply;
  422.                 pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->dataPbCount;
  423.                 pFWXNodeData->fcReplyBuffer[2] = ((UInt32 *) pMessage)[2];
  424.                 pFWXNodeData->fcReplyCommandObjectInUse = true;
  425.                 FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  426.                 FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  427.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  428.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  429.                                                 (Ptr) pFWXNodeData->fcReplyBuffer,
  430.                                                 kFlowControlSize);
  431.                 status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  432.                 if (status != noErr)
  433.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  434.             }
  435.             break;
  436.         
  437.         case kFCControlRequest:
  438.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  439.             {
  440.                 pFWXNodeData->fcReplyBuffer[0] = kFCControlReply;
  441.                 pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->controlPbCount;
  442.                 pFWXNodeData->fcReplyBuffer[2] = ((UInt32 *) pMessage)[2];
  443.                 pFWXNodeData->fcReplyCommandObjectInUse = true;
  444.                 FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  445.                 FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  446.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  447.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  448.                                                 (Ptr) pFWXNodeData->fcReplyBuffer,
  449.                                                 kFlowControlSize);
  450.                 status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  451.                 if (status != noErr)
  452.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  453.             }
  454.             break;
  455.         
  456.         case kFCDataReply:
  457.             fcPacketCount = ((UInt32 *) pMessage)[2];
  458.             CancelTimer(pFWXNodeData->fcTimerID, &fcRequestDelay);
  459.             if (fcPacketCount == pFWXNodeData->fcIndex)
  460.             {
  461.                 pFWXNodeData->fcIndex++;
  462.                 pFWXNodeData->dataPbAvail = ((SInt32 *) pMessage)[1];
  463.                 if (pFWXNodeData->dataPbAvail > 0)
  464.                 {
  465.                     if (pFWXNodeData->fcStopSend)
  466.                     {
  467.                         // there were no buffers before, now there are some, restart sending
  468.                         pFWXNodeData->fcStopSend = false;
  469.                         status = SendPacket(pFWXNodeData);
  470.                     }
  471.                 }
  472.                 else
  473.                 {
  474.                     // still no buffers available, reset timer
  475.                     fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  476.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  477.                                             RetryFlowControl,
  478.                                             (void *) pFWXNodeData,
  479.                                             &pFWXNodeData->fcTimerID);
  480.             }
  481.             }
  482.             else
  483.             {
  484.                 // received flow control message out of order, retry
  485.                 fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  486.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  487.                                             RetryFlowControl,
  488.                                             (void *) pFWXNodeData,
  489.                                             &pFWXNodeData->fcTimerID);
  490.             }
  491.             break;
  492.         
  493.         case kFCControlReply:
  494.             fcPacketCount = ((UInt32 *) pMessage)[2];
  495.             CancelTimer(pFWXNodeData->fcTimerID, &fcRequestDelay);
  496.             if (fcPacketCount == pFWXNodeData->fcIndex)
  497.             {
  498.                 pFWXNodeData->fcIndex++;
  499.                 pFWXNodeData->controlPbAvail = ((SInt32 *) pMessage)[1];
  500.                 if (pFWXNodeData->controlPbAvail > 0)
  501.                 {
  502.                     if (pFWXNodeData->fcStopSend)
  503.                     {
  504.                         pFWXNodeData->fcStopSend = false;
  505.                         status = SendPacket(pFWXNodeData);
  506.                     }
  507.                 }
  508.                 else
  509.                 {
  510.                     // still no buffers available, reset timer
  511.                     fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  512.                     status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  513.                                                 RetryFlowControl,
  514.                                                 (void *) pFWXNodeData,
  515.                                                 &pFWXNodeData->fcTimerID);
  516.                 }
  517.             }
  518.             else
  519.             {
  520.                 fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 10 milliseconds
  521.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  522.                                             RetryFlowControl,
  523.                                             (void *) pFWXNodeData,
  524.                                             &pFWXNodeData->fcTimerID);
  525.             }
  526.             break;
  527.         
  528.         case kAddressInfoRequest:
  529.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  530.             {
  531.             pFWXNodeData->remoteDataAddress.addressHi = ((UInt32 *) pMessage)[1];
  532.             pFWXNodeData->remoteDataAddress.addressLo = ((UInt32 *) pMessage)[2];
  533.             pFWXNodeData->fcReplyBuffer[0] = kAddressInfoReply;
  534.             pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->localDataAddress.addressHi;
  535.             pFWXNodeData->fcReplyBuffer[2] = pFWXNodeData->localDataAddress.addressLo;
  536.             pFWXNodeData->fcReplyCommandObjectInUse = true;
  537.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  538.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  539.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  540.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  541.                                             (Ptr) pFWXNodeData->fcReplyBuffer,
  542.                                             kFlowControlSize);
  543.             status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  544.                 if (status != noErr)
  545.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  546.             }
  547.             else
  548.             {
  549.                 FWDebugStr("\paddress info request, object in use");
  550.             }
  551.             break;
  552.             
  553.         case kAddressInfoReply:
  554.             pFWXNodeData->remoteDataAddress.addressHi = ((UInt32 *) pMessage)[1];
  555.             pFWXNodeData->remoteDataAddress.addressLo = ((UInt32 *) pMessage)[2];
  556.             break;
  557.             
  558.         default:
  559.             sprintf(debugStr,"fcNotify, message type unknown: %d", messageType);
  560.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  561.             break;
  562.     }
  563.         
  564.     if (status != noErr)
  565.     {
  566.         sprintf(debugStr,"fcNotify, error in FWWrite: %d", status);
  567.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  568.     }
  569. }
  570.  
  571. ////////////////////////////////////////////////////////////////////////////////
  572. //
  573. // HandleControlNotify
  574. //
  575. //    Handle notification of a control message received. If the message is data
  576. //    done, complete the data request, else complete the control request.
  577. //
  578.  
  579. static void HandleControlNotify (
  580.     FWXNodeDataPtr                pFWXNodeData,
  581.     Ptr                            pMessage,
  582.     UInt32                        msgLength)
  583. {
  584.     IOParamPtr                    pb;
  585.     UInt32                        packetType;
  586.     UInt32                        packetIndex;
  587.     OSStatus                    status = noErr;
  588.  
  589.     
  590.     packetIndex = ((UInt32 *) pMessage)[0];
  591.     if ((packetIndex > pFWXNodeData->lastIndex) || (packetIndex == 1))    // will be one if fwix is closed
  592.     {                                                                    // and opened on other machine
  593.         pFWXNodeData->lastIndex = packetIndex;
  594.         packetType = ((UInt32 *) pMessage)[1];
  595.     
  596.         if (packetType == kDataDone)
  597.         {
  598.                 HandleDataDone(pFWXNodeData, ((UInt32 *) pMessage)[2], ((UInt32 *) pMessage)[3]);
  599.         }
  600.         else
  601.         {        
  602.             // handle control packet
  603.             pb = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  604.             if (pb != nil)
  605.             {
  606.                 pFWXNodeData->controlPbCount--;
  607.                 if (pFWXNodeData->controlPbCount < 0)
  608.                     FWDebugStr("\pcontrol buffer count < 0, ControlNotify");
  609.                 PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pb);
  610.                 BlockMoveData(pMessage, pb->ioBuffer, msgLength);
  611.                 pb->ioActCount = msgLength;
  612.                 pb->ioMisc = (Ptr) packetType;
  613.                 FWXCommandIsComplete(pb, status);
  614.             }
  615.             else
  616.             {
  617.                 FWDebugStr("\pNo receive control buffer, WriteNotify");
  618.             }
  619.         }
  620.     }
  621.     else
  622.     {
  623.         sprintf(debugStr,"echo packet, last: %ld, received: %ld", pFWXNodeData->lastIndex, packetIndex);
  624.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  625.     }
  626. }
  627.     
  628. ////////////////////////////////////////////////////////////////////////////////
  629. //
  630. // HandleDataDone
  631. //
  632. //    Handle notification of a data done message. If the data completes the
  633. //    request, send the packet to the app. If the data overflows the request, send
  634. //    the current packet to the app and start a new one. Otherwise just copy the data
  635. //    into the current packet.
  636. //
  637.  
  638. static void HandleDataDone (
  639.     FWXNodeDataPtr                pFWXNodeData,
  640.     UInt32                        count,
  641.     UInt32                        checkSum)
  642. {
  643.     IOParamPtr                    pb;
  644.     UInt32                        byteCount;
  645.     UInt32                        dataSum;
  646.     OSStatus                    status = noErr;
  647.  
  648.     pb = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;    
  649.     if (pb != nil)
  650.     {
  651.         dataSum = 0;
  652.         for (byteCount = 0; byteCount < count; ++byteCount)
  653.             dataSum += (pFWXNodeData->dataBuffer)[byteCount];
  654.         
  655.         if (dataSum != checkSum)
  656.         {
  657.             status = badCksmErr;
  658.             sprintf(debugStr,"Checksum error, expected: %ld, received: %ld", checkSum, dataSum);
  659.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  660.         }
  661.         
  662.         BlockMoveData (pFWXNodeData->dataBuffer,
  663.                        pb->ioBuffer + pb->ioActCount,
  664.                        count);
  665.         pb->ioActCount += count;
  666.  
  667.         pFWXNodeData->dataPbCount--;
  668.         if (pFWXNodeData->dataPbCount < 0)
  669.             FWDebugStr("\pdataPbCount < 0, data done");
  670.  
  671.             PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pb);
  672.             pb->ioMisc = (Ptr) kForkData;
  673.             FWXCommandIsComplete(pb, status);
  674.         }
  675.     else
  676.         FWDebugStr("\pNo receive buffer for data, data done");
  677. }
  678.  
  679.  
  680. ////////////////////////////////////////////////////////////////////////////////
  681. //
  682. // FWPDriverUnitAdded
  683. //
  684. //   FireWire protocol driver interface for handling added units.
  685. //
  686.  
  687. static OSStatus    FWPDriverUnitAdded(
  688.     FWPDriverID                    fwPDriverID,
  689.     UInt32                        fwPDriverSpecificData,
  690.     FWUnitID                    fwUnitID)
  691. {
  692.     FWXDriverDataPtr            pFWXDriverData;
  693.     OSStatus                    status = noErr;
  694.  
  695.     // Get our driver data.
  696.     pFWXDriverData = (FWXDriverDataPtr) fwPDriverSpecificData;
  697.  
  698.     status = RegisterFWXNode (pFWXDriverData->fwxDriverID, (UInt32) fwUnitID);
  699.  
  700.     return (status);
  701. }
  702.  
  703. ////////////////////////////////////////////////////////////////////////////////
  704. //
  705. // FWPDriverUnitRemoved
  706. //
  707. //   FireWire protocol driver interface for handling removed units.
  708. //
  709.  
  710. static OSStatus    FWPDriverUnitRemoved(
  711.     FWPDriverID                    fwPDriverID,
  712.     UInt32                        fwPDriverSpecificData,
  713.     FWUnitID                    fwUnitID)
  714. {
  715.     FWXDriverDataPtr            pFWXDriverData;
  716.     OSStatus                    status = noErr;
  717.  
  718.     // Get our driver data.
  719.     pFWXDriverData = (FWXDriverDataPtr) fwPDriverSpecificData;
  720.  
  721.     status = UnregisterFWXNode (pFWXDriverData->fwxDriverID, (UInt32) fwUnitID);
  722.  
  723.     return (status);
  724. }
  725.  
  726.  
  727. ////////////////////////////////////////////////////////////////////////////////
  728. //
  729. //    FlowControlCompletion
  730. //
  731. //    Completion routine for flow control message write
  732. //
  733.  
  734. static void FlowControlComplete(
  735.     FWCommandObjectID            fwCommandObjectID,
  736.     OSStatus                    commandStatus,
  737.     UInt32                        completionProcData)
  738. {
  739.     FWXNodeDataPtr            pFWXNodeData;
  740.  
  741.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  742.     pFWXNodeData->fcSendCommandObjectInUse = false;
  743.     if (commandStatus != noErr)
  744.     {
  745.         if ((commandStatus == timeoutErr) ||
  746.             (commandStatus == retryExceededErr) ||
  747.             (commandStatus == busReconfiguredErr))
  748.         {
  749.             pFWXNodeData->fcSendCommandObjectInUse = true;
  750.             commandStatus = FWWrite(fwCommandObjectID);
  751.             if (commandStatus != noErr)
  752.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  753.         }
  754.         else
  755.         {
  756.         sprintf(debugStr,"Error in send flow control: %ld", commandStatus);
  757.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  758.     }
  759.     }
  760. }
  761.  
  762.  
  763. ////////////////////////////////////////////////////////////////////////////////
  764. //
  765. //    FlowControlReplyComplete
  766. //
  767. //    Completion routine for flow control reply write
  768. //
  769.  
  770. static void FlowControlReplyComplete(
  771.     FWCommandObjectID            fwCommandObjectID,
  772.     OSStatus                    commandStatus,
  773.     UInt32                        completionProcData)
  774. {
  775.     FWXNodeDataPtr            pFWXNodeData;
  776.  
  777.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  778.     pFWXNodeData->fcReplyCommandObjectInUse = false;
  779.     if (commandStatus != noErr)
  780.     {
  781.         if ((commandStatus == timeoutErr) ||
  782.             (commandStatus == retryExceededErr) ||
  783.             (commandStatus == busReconfiguredErr))
  784.         {
  785.             commandStatus = FWWrite(fwCommandObjectID);
  786.             if (commandStatus != noErr)
  787.                 pFWXNodeData->fcReplyCommandObjectInUse = false;
  788.         }
  789.         else
  790.         {
  791.         sprintf(debugStr,"Error in send flow control: %ld", commandStatus);
  792.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  793.     }
  794.     }
  795. }
  796.  
  797.  
  798. ////////////////////////////////////////////////////////////////////////////////
  799. //
  800. //    FWXRead
  801. //
  802. //    FWiX read routine. This is not a FireWire read routine. This is an
  803. //    interface for the FwiX application to pass read buffers to the
  804. //    driver to handle received data.
  805. //
  806. //    Queue the application parameter    blocks. The FWClientWriteCompleteInterface
  807. //    routine handles the rest. A counter keeps the number of read control parameter
  808. //    blocks which will tell the sender how many control commands it can send.
  809. //    Also keep up with the size of the data buffer to tell the sender how much
  810. //    data can be sent.
  811. //
  812.  
  813. static OSStatus FWXRead(
  814.     FWXAsynchParamsPtr        pFWXAsynchParams)
  815. {
  816.     FWXNodeDataPtr            pFWXNodeData;
  817.     IOParamPtr                pIOParam;
  818.     OSStatus                status = noErr;
  819.  
  820.     pFWXNodeData = (FWXNodeDataPtr) pFWXAsynchParams->fwxInterfaceParams.pNodeSpecificData;
  821.     pIOParam = pFWXAsynchParams->pIOPB;
  822.     
  823.     pIOParam->ioActCount = 0;
  824.     if (pIOParam->ioMisc == (Ptr) kForkData)
  825.     {
  826.         status = PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pReadDataQHdr);
  827.         pFWXNodeData->dataPbCount++;
  828.         if (pFWXNodeData->dataPbCount > 6)        // value from fwixmain.h
  829.             FWDebugStr("\pdata buffer count too high, FWXRead");
  830.     }
  831.     else
  832.     {
  833.         status = PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pReadControlQHdr);
  834.         pFWXNodeData->controlPbCount++;
  835.         if (pFWXNodeData->dataPbCount > 20)        // value from fwixmain.h
  836.             FWDebugStr("\pcontrol buffer count too high, FWXRead");
  837.     }
  838.         
  839.     return status;
  840. }
  841.  
  842.  
  843. ////////////////////////////////////////////////////////////////////////////////
  844. //
  845. //    FWXWrite
  846. //
  847. //    Queue the write request. If there are no writes in progress, go ahead and
  848. //    issue a write. Otherwise the queued write request will be picked up by
  849. //    the write completion routine.
  850. //
  851.  
  852. static OSStatus FWXWrite(
  853.     FWXAsynchParamsPtr        pFWXAsynchParams)
  854. {
  855.     FWXNodeDataPtr            pFWXNodeData;
  856.     IOParamPtr                pIOParam;
  857.     OSStatus                status = noErr;
  858.  
  859.     // recover driver data
  860.     pFWXNodeData = (FWXNodeDataPtr) pFWXAsynchParams->fwxInterfaceParams.pNodeSpecificData;
  861.     pIOParam = pFWXAsynchParams->pIOPB;
  862.  
  863.     // queue the parameter block
  864.     pIOParam->ioActCount = 0;
  865.     PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pWriteQHdr);
  866.     
  867.     if (!pFWXNodeData->writePending)
  868.     {    
  869.         pIOParam = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  870.         if (pIOParam != nil)
  871.         {
  872.             pFWXNodeData->writePending = true;    
  873.             pFWXNodeData->pCurIOParam = pIOParam;
  874.             status = SendPacket(pFWXNodeData);
  875.         }
  876.     }
  877.     return status;
  878. }
  879.  
  880.  
  881. ////////////////////////////////////////////////////////////////////////////////
  882. //
  883. //    DataDoneComplete
  884. //
  885. //    Data done complete routine. Set completion routine back to write complete
  886. //    for asynchCommandObject. Try sending another packet.
  887. //
  888.  
  889. static void DataDoneComplete(
  890.     FWCommandObjectID            fwCommandObjectID,
  891.     OSStatus                    commandStatus,
  892.     UInt32                        completionProcData)
  893. {
  894.     FWXNodeDataPtr                pFWXNodeData;
  895.     IOParamPtr                    pb;
  896.  
  897.     // recover node data
  898.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  899.  
  900.     // make sure node connection is still open
  901.     if (pFWXNodeData->closed)
  902.         commandStatus = notOpenErr;
  903.  
  904.     if (commandStatus == noErr)
  905.     {
  906.         FWSetFWCommandCompletionProc (fwCommandObjectID, FWXWriteCompletion);
  907.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  908.  
  909.         // check the queue for more parameter blocks to send
  910.         pb = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  911.         pFWXNodeData->pCurIOParam = pb;
  912.         if (pb != nil)
  913.             SendPacket(pFWXNodeData);
  914.         else
  915.             pFWXNodeData->writePending = false;
  916.     }
  917.     else if ((commandStatus == timeoutErr) ||
  918.             (commandStatus == retryExceededErr) ||
  919.             (commandStatus == busReconfiguredErr))
  920.     {
  921.         // try sending again
  922.         commandStatus = FWWrite(fwCommandObjectID);
  923.         if (commandStatus != noErr)
  924.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  925.     }
  926.     else
  927.     {
  928.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  929.         sprintf(debugStr, "Error in data done complete: %ld", commandStatus);
  930.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  931.     }
  932. }
  933.  
  934. ////////////////////////////////////////////////////////////////////////////////
  935. //
  936. //    HandleWriteDataComplete
  937. //
  938. //    Write data completion routine. If all of the requested data in the
  939. //    current parameter block has been sent, complete the command then
  940. //    dequeue another request and start sending it. If there are no requests
  941. //    waiting, set write complete to true and the next write request will restart
  942. //    the write/write complete loop.
  943. //
  944.  
  945. static void HandleWriteDataComplete(
  946.     FWCommandObjectID            fwCommandObjectID,
  947.     FWXNodeDataPtr                pFWXNodeData,
  948.     IOParamPtr                    pCompleteIOPb)
  949. {
  950.     IOParamPtr                    doneIOParam;
  951.     Ptr                            dataSent;
  952.     UInt32                        dataSum;
  953.     UInt32                        actCount;
  954.     UInt32                        byteCount;
  955.     OSStatus                    status;
  956.  
  957.     FWGetAsynchCommandBytesTransferred(fwCommandObjectID, &actCount);
  958.     pCompleteIOPb->ioActCount += actCount;
  959.     pFWXNodeData->dataPbAvail = 0;            // turn off flow control to allow for time
  960.                                             // for receiver to read data out of buffer
  961.     
  962.     pFWXNodeData->writeAsynchCommandObjectInUse    = false;
  963.     
  964.     FWGetAsynchCommandBuffer(fwCommandObjectID, &dataSent);
  965.     dataSum = 0;
  966.     for (byteCount = 0; byteCount < actCount; ++byteCount)
  967.         dataSum += dataSent[byteCount];
  968.     
  969.     pFWXNodeData->controlIndex++;
  970.     pFWXNodeData->dataDoneBuffer[0] = pFWXNodeData->controlIndex;
  971.  
  972.     // set packet type, data sent length, checksum
  973.     pFWXNodeData->dataDoneBuffer[1] = kDataDone;
  974.     pFWXNodeData->dataDoneBuffer[2] = actCount;
  975.     pFWXNodeData->dataDoneBuffer[3] = dataSum;
  976.  
  977.     if (!pFWXNodeData->writeAsynchCommandObjectInUse)
  978.     {
  979.     pFWXNodeData->writeAsynchCommandObjectInUse = true;
  980.     FWSetFWCommandCompletionProcData (fwCommandObjectID, (UInt32) pFWXNodeData);
  981.     FWSetCommonAsynchCommandParams (fwCommandObjectID,
  982.                                     pFWXNodeData->fwxUnitInfo.controlAddress.addressHi,
  983.                                     pFWXNodeData->fwxUnitInfo.controlAddress.addressLo,
  984.                                     (Ptr) pFWXNodeData->dataDoneBuffer,
  985.                                     kDataDoneBufSize);
  986.     FWSetFWCommandCompletionProc (fwCommandObjectID, DataDoneComplete);
  987.     
  988.         // send the data done notification after dequeuing the packet
  989.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  990.         if (status != noErr)
  991.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  992.         
  993.     // if all of the requested data was not sent, send some more
  994.     if (pCompleteIOPb->ioActCount < pCompleteIOPb->ioReqCount)
  995.     {
  996.         FWDebugStr("\pwrite data complete, should not be here");
  997.         SendPacket(pFWXNodeData);
  998.     }
  999.     else
  1000.     {
  1001.         // completed sending this parameter block, dequeue it and complete
  1002.         PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1003.         if (doneIOParam->ioCmdAddr != pCompleteIOPb->ioCmdAddr)
  1004.             FWDebugStr("\pWrite completion, queued pb not the same as completed pb");
  1005.         pFWXNodeData->pCurIOParam = nil;
  1006.         FWXCommandIsComplete(doneIOParam, noErr);
  1007.     }
  1008.     
  1009.     }
  1010.     else
  1011.         FWDebugStr("\pWriteDataComplete, writeAsynchCommandObjectInUse");
  1012. }
  1013.  
  1014. ////////////////////////////////////////////////////////////////////////////////
  1015. //
  1016. //    HandleWriteControlComplete
  1017. //
  1018. //    Write control completion routine. Complete the command then
  1019. //    dequeue another request and start sending it. If there are no requests
  1020. //    waiting, set write complete to true and the next write request will restart
  1021. //    the write/write complete loop.
  1022. //
  1023.  
  1024. static void HandleWriteControlComplete(
  1025.     FWCommandObjectID            fwCommandObjectID,
  1026.     FWXNodeDataPtr                pFWXNodeData,
  1027.     IOParamPtr                    pCompleteIOPb)
  1028. {
  1029.     IOParamPtr                    doneIOParam;
  1030.     UInt32                        actCount;            // count of bytes transferred
  1031.     OSErr                        err;
  1032.  
  1033.     FWGetAsynchCommandBytesTransferred(fwCommandObjectID, &actCount);
  1034.     pCompleteIOPb->ioActCount += actCount;
  1035.     
  1036.     // completed sending this parameter block, dequeue it and complete
  1037.     err = PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1038.     if (doneIOParam->ioCmdAddr != pCompleteIOPb->ioCmdAddr)
  1039.         FWDebugStr("\pWriteControlComplete, queued pb not the same as completed pb");
  1040.  
  1041.     FWXCommandIsComplete(doneIOParam, noErr);
  1042.     pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1043.     
  1044.     // check the queue for more parameter blocks to send
  1045.     pCompleteIOPb = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1046.     pFWXNodeData->pCurIOParam = pCompleteIOPb;
  1047.     if (pCompleteIOPb != nil)
  1048.         SendPacket(pFWXNodeData);
  1049.     else
  1050.         pFWXNodeData->writePending = false;
  1051. }
  1052.  
  1053. ////////////////////////////////////////////////////////////////////////////////
  1054. //
  1055. //    FWXWriteCompletion
  1056. //
  1057. //    FWiX write completion routine. If all of the requested data in the
  1058. //    current parameter block has been sent, complete the command then
  1059. //    dequeue another request and start sending it. If there are no requests
  1060. //    waiting, set write complete to true and the next write request will restart
  1061. //    the write/write complete loop.
  1062. //
  1063.  
  1064. static void FWXWriteCompletion(
  1065.     FWCommandObjectID            fwCommandObjectID,
  1066.     OSStatus                    commandStatus,
  1067.     UInt32                        completionProcData)
  1068. {
  1069.     FWXNodeDataPtr                pFWXNodeData;
  1070.     IOParamPtr                    pIOParam;            // param block being processed
  1071.     IOParamPtr                    doneIOParam;        // param block being processed
  1072.  
  1073.     // recover original parameter block 
  1074.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  1075.     pIOParam = pFWXNodeData->pCurIOParam;
  1076.  
  1077.     // make sure node connection is still open
  1078.     if (pFWXNodeData->closed)
  1079.         commandStatus = notOpenErr;
  1080.  
  1081.     // check transfer stats and increment actual bytes transferred
  1082.     if (commandStatus == noErr)
  1083.     {
  1084.         if (pIOParam->ioMisc == (Ptr) kForkData)
  1085.             HandleWriteDataComplete(fwCommandObjectID, pFWXNodeData, pIOParam);
  1086.         else
  1087.             HandleWriteControlComplete(fwCommandObjectID, pFWXNodeData, pIOParam);
  1088.     }
  1089.     else if ((commandStatus == timeoutErr) ||
  1090.             (commandStatus == retryExceededErr) ||
  1091.             (commandStatus == busReconfiguredErr))
  1092.     {
  1093.         // got a timeout error, try sending again
  1094.         //sprintf(debugStr, "Timeout error in WriteCompletion, pb: %lx", pIOParam);
  1095.         //FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1096.         SendPacket(pFWXNodeData);
  1097.     }
  1098.     else
  1099.     {
  1100.         // completion routine got an error
  1101.         sprintf(debugStr,"Error in write complete: %ld", commandStatus);
  1102.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1103.  
  1104.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1105.         PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1106.         pFWXNodeData->writePending = false;
  1107.         FWXCommandIsComplete(doneIOParam, commandStatus);
  1108.     }
  1109. }
  1110.  
  1111. ////////////////////////////////////////////////////////////////////////////////
  1112. //
  1113. //    RetryFlowControl
  1114. //
  1115. //    Timer-based routine to request if transmit continue. Check to see if
  1116. //    data transmit or control transmit is held and send appropriate request.
  1117. //
  1118. // JKL *** can another flow control write be pending? What if there is no
  1119. //    response?
  1120. //
  1121.  
  1122. static OSStatus RetryFlowControl(
  1123.     void                *p1,        // node data
  1124.     void                *p2)
  1125. {
  1126.     FWXNodeDataPtr        pFWXNodeData;
  1127.     IOParamPtr            pb;
  1128.     OSStatus            status = noErr;
  1129.     
  1130.     pFWXNodeData = (FWXNodeDataPtr) p1;
  1131.     pb = pFWXNodeData->pCurIOParam;
  1132.  
  1133.     // make sure node connection is still open
  1134.     if (pFWXNodeData->closed)
  1135.         status = notOpenErr;
  1136.  
  1137.     if ((status == noErr) && (!pFWXNodeData->fcSendCommandObjectInUse))
  1138.     {
  1139.         if (pb->ioMisc == (Ptr) kForkData)
  1140.             pFWXNodeData->fcSendBuffer[0] = kFCDataRequest;
  1141.         else
  1142.             pFWXNodeData->fcSendBuffer[0] = kFCControlRequest;
  1143.             
  1144.         pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1145.         pFWXNodeData->fcSendCommandObjectInUse = true;
  1146.         FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1147.         FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1148.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1149.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1150.                                         (Ptr) pFWXNodeData->fcSendBuffer,
  1151.                                         kFlowControlSize);
  1152.         status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1153.         if (status != noErr)
  1154.         {
  1155.             pFWXNodeData->fcSendCommandObjectInUse = false;
  1156.         }
  1157.     }
  1158.     else
  1159.     {
  1160.         sprintf(debugStr,"Error in retry flow control: %ld", status);
  1161.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1162.     }
  1163.     return status;
  1164. }
  1165.  
  1166. ////////////////////////////////////////////////////////////////////////////////
  1167. //
  1168. //    SendDataPacket
  1169. //
  1170. //    Send a data packet. If the receive available packet counter is 0
  1171. //    then send a flow control request to the receiver to get the number
  1172. //    of receive buffers available.
  1173. //
  1174. static OSStatus SendDataPacket(
  1175.     FWXNodeDataPtr            pFWXNodeData,
  1176.     IOParamPtr                pb,
  1177.     UInt32                    length)
  1178. {
  1179.     OSStatus                status = noErr;
  1180.  
  1181.     if (pFWXNodeData->dataPbAvail > 0)
  1182.     {
  1183.         pFWXNodeData->dataPbAvail--;
  1184.         pFWXNodeData->writeAsynchCommandObjectInUse = true;
  1185.         FWSetFWCommandCompletionProcData (pFWXNodeData->writeAsynchCommandObjectID, (UInt32) pFWXNodeData);
  1186.         FWSetCommonAsynchCommandParams  (pFWXNodeData->writeAsynchCommandObjectID,
  1187.                                         pFWXNodeData->remoteDataAddress.addressHi,
  1188.                                         pFWXNodeData->remoteDataAddress.addressLo,
  1189.                                         pb->ioBuffer + pb->ioActCount,        // increment buffer address
  1190.                                         length);
  1191.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  1192.         if (status != noErr)
  1193.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1194.     }
  1195.     else
  1196.     {
  1197.         pFWXNodeData->fcStopSend = true;
  1198.         
  1199.         // JKL *** can another flow control write be pending? What if there is no
  1200.         //    response?
  1201.         if (!pFWXNodeData->fcSendCommandObjectInUse)
  1202.         {
  1203.             pFWXNodeData->fcSendBuffer[0] = kFCDataRequest;
  1204.             pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1205.             pFWXNodeData->fcSendCommandObjectInUse = true;
  1206.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1207.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1208.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1209.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1210.                                             (Ptr) pFWXNodeData->fcSendBuffer,
  1211.                                             kFlowControlSize);
  1212.             status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1213.             if (status != noErr)
  1214.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  1215.         }
  1216.     }
  1217.     return status;
  1218. }
  1219.  
  1220. ////////////////////////////////////////////////////////////////////////////////
  1221. //
  1222. //    SendControlPacket
  1223. //
  1224. //    Send a control packet. Make sure a control packet is allowed. If none
  1225. //    are allowed packet will be sent once allowed notification is received.
  1226. //
  1227.  
  1228. static OSStatus SendControlPacket(
  1229.     FWXNodeDataPtr            pFWXNodeData,
  1230.     IOParamPtr                pb,
  1231.     UInt32                    length)
  1232. {
  1233.     OSStatus                status = noErr;
  1234.  
  1235.     if (pFWXNodeData->controlPbAvail > 0)
  1236.     {
  1237.         pFWXNodeData->controlPbAvail--;
  1238.         pFWXNodeData->controlIndex++;
  1239.         *((UInt32 *) pb->ioBuffer) = pFWXNodeData->controlIndex;
  1240.         length += 4;
  1241.  
  1242.         pFWXNodeData->writeAsynchCommandObjectInUse = true;
  1243.         FWSetFWCommandCompletionProcData (pFWXNodeData->writeAsynchCommandObjectID, (UInt32) pFWXNodeData);
  1244.         FWSetCommonAsynchCommandParams (pFWXNodeData->writeAsynchCommandObjectID,
  1245.                                         pFWXNodeData->fwxUnitInfo.controlAddress.addressHi,
  1246.                                         pFWXNodeData->fwxUnitInfo.controlAddress.addressLo,
  1247.                                         pb->ioBuffer,
  1248.                                         length);
  1249.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  1250.         if (status != noErr)
  1251.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1252.     }
  1253.     else
  1254.     {
  1255.         pFWXNodeData->fcStopSend = true;
  1256.  
  1257.         // JKL *** can another flow control write be pending? What if there is no
  1258.         //    response?
  1259.         if (!pFWXNodeData->fcSendCommandObjectInUse)
  1260.         {
  1261.             pFWXNodeData->fcSendBuffer[0] = kFCControlRequest;
  1262.             pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1263.             pFWXNodeData->fcSendCommandObjectInUse = true;
  1264.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1265.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1266.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1267.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1268.                                             (Ptr) pFWXNodeData->fcSendBuffer,
  1269.                                             kFlowControlSize);
  1270.             status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1271.             if (status != noErr)
  1272.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  1273.         }
  1274.     }
  1275.     return status;
  1276. }
  1277.  
  1278. ////////////////////////////////////////////////////////////////////////////////
  1279. //
  1280. //    SendPacket
  1281. //
  1282. //    Check for the packet needs data to be sent. Pass it off to the senddata
  1283. //    or sendcontrol routine. If no data, complete the command.
  1284. //
  1285.  
  1286. static OSStatus SendPacket(
  1287.     FWXNodeDataPtr            pFWXNodeData)
  1288. {
  1289.     IOParamPtr                pb;
  1290.     OSStatus                status = noErr;
  1291.  
  1292.     if     (pFWXNodeData->fcStopSend)
  1293.         FWDebugStr("\pIn SendPacket with stop flow control");
  1294.  
  1295.     pb = pFWXNodeData->pCurIOParam;
  1296.     if (pb != nil) 
  1297.     {
  1298.         if (pb->ioMisc == (Ptr) kForkData)
  1299.             status = SendDataPacket(pFWXNodeData, pb, pb->ioReqCount);
  1300.         else
  1301.             status = SendControlPacket(pFWXNodeData, pb, pb->ioReqCount);
  1302.     }
  1303.  
  1304.     return status;
  1305. }
  1306.  
  1307. ////////////////////////////////////////////////////////////////////////////////
  1308. //
  1309. //    FWXDriverInterface
  1310. //
  1311. //    Main FireWire File Exchange driver interface.
  1312. //
  1313.  
  1314. OSStatus FWXDriverInterface (
  1315.     FWXInterfaceParamsPtr        pFWXInterfaceParams)
  1316. {
  1317.     FWXNodeDataPtr                pFWXNodeData;
  1318.     IOParamPtr                    pIOPB;
  1319.     UInt32                        interfaceSelector;
  1320.     OSStatus                    err = noErr;
  1321.  
  1322.     // Get our driver and node info
  1323.     pFWXNodeData =
  1324.         (FWXNodeDataPtr) pFWXInterfaceParams->pNodeSpecificData;
  1325.     interfaceSelector = pFWXInterfaceParams->interfaceSelector;
  1326.  
  1327.     // Main dispatch.
  1328.     switch (interfaceSelector) {
  1329.  
  1330.         case kFWXInitialize :
  1331.             err = FWXInitialize((FWXInitializeParamsPtr) pFWXInterfaceParams);
  1332.             break;
  1333.  
  1334.         case kFWXTerminate :
  1335.             err = FWXTerminate((FWXTerminateParamsPtr) pFWXInterfaceParams);
  1336.             break;
  1337.  
  1338.         case kFWXWrite :
  1339.             err = FWXWrite((FWXAsynchParamsPtr) pFWXInterfaceParams);
  1340.             break;
  1341.  
  1342.         case kFWXRead :
  1343.             err = FWXRead((FWXAsynchParamsPtr) pFWXInterfaceParams);
  1344.             break;
  1345.  
  1346.         case kFWXKillIO :
  1347.             pFWXNodeData->writePending = false;
  1348.             
  1349.             // clean up any pending reads
  1350.             err = PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1351.             while ((pIOPB != nil) && (err == noErr)) {
  1352.                 pIOPB->ioActCount = 0;
  1353.                 FWXCommandIsComplete(pIOPB, noErr);
  1354.                 err = PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1355.             }
  1356.             
  1357.             err = PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1358.             while ((pIOPB != nil) && (err == noErr)) {
  1359.                 pIOPB->ioActCount = 0;
  1360.                 FWXCommandIsComplete(pIOPB, noErr);
  1361.                 err = PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1362.             }
  1363.             pFWXNodeData->dataPbCount = 0;
  1364.             pFWXNodeData->controlPbCount = 0;
  1365.             pFWXNodeData->dataPbAvail = 0;
  1366.             pFWXNodeData->controlPbAvail = 0;
  1367.             break;
  1368.  
  1369.         case kFWXOpenNode:
  1370.             err = FWXOpenNode((FWXOpenNodeParamsPtr) pFWXInterfaceParams);
  1371.             break;
  1372.  
  1373.         case kFWXCloseNode:
  1374.             err = FWXCloseNode((FWXNodeDataPtr) (pFWXInterfaceParams->pNodeSpecificData));
  1375.             break;
  1376.  
  1377.         default :
  1378.             err = paramErr;
  1379.             break;
  1380.     }
  1381.  
  1382.     return err;
  1383. }
  1384.  
  1385. ////////////////////////////////////////////////////////////////////////////////
  1386. //
  1387. //    FWXInitialize
  1388. //
  1389. //    This routine initializes the FireWire File Exchange driver.  It
  1390. //    allocates a private data record and registers with the FireWire family.
  1391. //
  1392.  
  1393. static OSStatus FWXInitialize(
  1394.     FWXInitializeParamsPtr        pFWXInitializeParams)
  1395. {
  1396.     FWPDriverProtocol            fwPDriverProtocolTable[1];
  1397.     Ptr                            pBuffer = nil;
  1398.     FWXDriverDataPtr            pFWXDriverData;
  1399.     OSStatus                    status = noErr;
  1400.     
  1401. //    FWDebugStr("\pfwix driver init");
  1402.     // Allocate driver data.
  1403.     pFWXDriverData = (FWXDriverDataPtr) PoolAllocateResident(sizeof(FWXDriverData), true);
  1404.     if (pFWXDriverData != nil)
  1405.         pFWXDriverData->fwxDriverID = pFWXInitializeParams->fwxDriverID;
  1406.     else
  1407.         status = memFullErr;
  1408.  
  1409.     // Allocate a control buffer
  1410.     if (status == noErr)
  1411.     {
  1412.         pBuffer = PoolAllocateResident(kFWControlBufferSize, false);
  1413.         if (pBuffer == nil)
  1414.         {
  1415.             PoolDeallocate((Ptr) pFWXDriverData);
  1416.             pFWXDriverData = nil;
  1417.             status = memFullErr;
  1418.         }
  1419.         else
  1420.             pFWXDriverData->controlBuffer = pBuffer;
  1421.     }
  1422.  
  1423.     // Allocate a flow control receive buffer
  1424.     if (status == noErr)
  1425.     {
  1426.         pBuffer = PoolAllocateResident(kFlowControlSize, true);
  1427.         if (pBuffer == nil)
  1428.         {
  1429.             PoolDeallocate(pFWXDriverData->controlBuffer);
  1430.             PoolDeallocate((Ptr) pFWXDriverData);
  1431.             pFWXDriverData = nil;
  1432.             status = memFullErr;
  1433.         }
  1434.         else
  1435.             pFWXDriverData->fcBuffer = pBuffer;
  1436.     }
  1437.  
  1438.     // Register with the FireWire family.
  1439.     if (status == noErr)
  1440.     {
  1441.         status = FWRegisterProtocolDriver (pFWXInitializeParams->pDriverRegEntry,
  1442.                                            &(pFWXDriverData->fwPDriverID),
  1443.                                            (UInt32) pFWXDriverData);
  1444.     }
  1445.  
  1446.     // Set protocol table.
  1447.     if (status == noErr)
  1448.     {
  1449.         fwPDriverProtocolTable[0].specID = 'app';
  1450.         fwPDriverProtocolTable[0].swVersion = 'fwx';
  1451.         status = FWSetPDriverProtocolTable (pFWXDriverData->fwPDriverID,
  1452.                                             &fwPDriverProtocolTable[0],
  1453.                                             1);
  1454.     }
  1455.  
  1456.     // Set unit notification procs.
  1457.     if (status == noErr)
  1458.     {
  1459.         status = FWSetFWPDriverUnitAddedProc (pFWXDriverData->fwPDriverID,
  1460.                                               FWPDriverUnitAdded);
  1461.     }
  1462.     if (status == noErr)
  1463.     {
  1464.         status = FWSetFWPDriverUnitRemovedProc (pFWXDriverData->fwPDriverID,
  1465.                                                 FWPDriverUnitRemoved);
  1466.     }
  1467.  
  1468.     // Scan for units.
  1469.     if (status == noErr)
  1470.         status = FWScanUnitsForFWPDriver (pFWXDriverData->fwPDriverID);
  1471.  
  1472.     // set driver write notify routine
  1473.     if (status == noErr)
  1474.     {
  1475.         status = FWSetFWClientWriteCompleteProc((FWReferenceID) pFWXDriverData->fwPDriverID,
  1476.                                                 FWClientWriteCompleteInterface);
  1477.     }
  1478.  
  1479.     // Get address space for control buffer: allow write and notify on write
  1480.     if (status == noErr)
  1481.     {
  1482.         status = FWAllocateAddressSpace
  1483.                     (&pFWXDriverData->controlAddressSpaceID,
  1484.                      (FWReferenceID) pFWXDriverData->fwPDriverID,
  1485.                      &(pFWXDriverData->controlAddress),
  1486.                      kFWControlBufferSize,
  1487.                      pFWXDriverData->controlBuffer,
  1488.                      kFWAddressWriteEnable | kFWAddressWriteCompleteNotify,
  1489.                      (Ptr) pFWXDriverData);
  1490.     }
  1491.  
  1492.     // Get address space for flow control buffer: allow write, notify on write
  1493.     if (status == noErr)
  1494.     {
  1495.         status = FWAllocateAddressSpace
  1496.                     (&pFWXDriverData->fcAddressSpaceID,
  1497.                      (FWReferenceID) pFWXDriverData->fwPDriverID,
  1498.                      &(pFWXDriverData->fcAddress),
  1499.                      kFlowControlSize,
  1500.                      (Ptr) pFWXDriverData->fcBuffer,
  1501.                      kFWAddressWriteEnable | kFWAddressWriteCompleteNotify,
  1502.                      (Ptr) pFWXDriverData);
  1503.     }
  1504.  
  1505.     // Create a unit directory.
  1506.     if (status == noErr)
  1507.     {
  1508.         status = FWXCreatePDriverUnitDirectory (pFWXDriverData,
  1509.                                                 &(pFWXDriverData->unitCSRROMEntryID));
  1510.     }
  1511.  
  1512.  
  1513.     // Save our driver data or clean up on error.
  1514.     if (status == noErr)
  1515.     {
  1516.         pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData =
  1517.             (Ptr) pFWXDriverData;
  1518.     }
  1519.     else
  1520.     {
  1521.         //zzz should use terminate
  1522.         // deallocate more stuff, asynch object?
  1523.         if (pFWXDriverData->fcBuffer != nil)
  1524.             PoolDeallocate((Ptr) pFWXDriverData->fcBuffer);
  1525.         if (pFWXDriverData->controlBuffer != nil)
  1526.             PoolDeallocate(pFWXDriverData->controlBuffer);
  1527.         if (pFWXDriverData != nil)
  1528.             PoolDeallocate((Ptr) pFWXDriverData);
  1529.  
  1530.         pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData = nil;
  1531.     }
  1532.     return status;
  1533. }
  1534.  
  1535.  
  1536. ////////////////////////////////////////////////////////////////////////////////
  1537. //
  1538. // FWXCreatePDriverUnitDirectory
  1539. //
  1540. //   This routine adds a Configuration ROM unit directory for the protocol driver.
  1541. //zzz must do cleanup on error.
  1542. //
  1543.  
  1544. static OSStatus    FWXCreatePDriverUnitDirectory(
  1545.     FWXDriverDataPtr            pFWXDriverData,
  1546.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID)
  1547. {
  1548.     CSRROMEntryID                csrROMRootEntryID = kInvalidCSRROMEntryID,
  1549.                                 csrROMUnitDirEntryID = kInvalidCSRROMEntryID,
  1550.                                 csrROMEntryID = kInvalidCSRROMEntryID;
  1551.     FWXUnitInfo                    fwxUnitInfo;
  1552.     UInt32                        immediateEntry;
  1553.     OSStatus                    status = noErr;
  1554.  
  1555.     // Get configuration ROM root directory.
  1556.     status = FWCSRROMGetRootDirectory (pFWXDriverData->fwPDriverID, &csrROMRootEntryID);
  1557.  
  1558.     // Create a new unit directory.
  1559.     if (status == noErr)
  1560.     {
  1561.         status = FWCSRROMCreateEntry (csrROMRootEntryID,
  1562.                                       &csrROMUnitDirEntryID,
  1563.                                       kDirectoryCSRROMEntryType,
  1564.                                       kCSRUnitDirectoryKey,
  1565.                                       nil,
  1566.                                       0);
  1567.         if (status == noErr)
  1568.             pFWXDriverData->unitCSRROMEntryID = csrROMUnitDirEntryID;
  1569.     }
  1570.  
  1571.     // Set unit's spec ID.
  1572.     if (status == noErr)
  1573.     {
  1574.         immediateEntry = 'app ';
  1575.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1576.                                       &csrROMEntryID,
  1577.                                       kImmediateCSRROMEntryType,
  1578.                                       kCSRUnitSpecIdKey,
  1579.                                       (Ptr) &immediateEntry,
  1580.                                       3);
  1581.     }
  1582.  
  1583.     // Set unit's SW Version.
  1584.     if (status == noErr)
  1585.     {
  1586.         immediateEntry = 'fwx ';
  1587.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1588.                                       &csrROMEntryID,
  1589.                                       kImmediateCSRROMEntryType,
  1590.                                       kCSRUnitSwVersionKey,
  1591.                                       (Ptr) &immediateEntry,
  1592.                                       3);
  1593.     }
  1594.  
  1595.     // Create unit dependent leaf.
  1596.     if (status == noErr)
  1597.     {
  1598.         // Fill in data for FWiX unit info leaf.
  1599.         fwxUnitInfo.controlAddress.addressHi = pFWXDriverData->controlAddress.addressHi;
  1600.         fwxUnitInfo.controlAddress.addressLo = pFWXDriverData->controlAddress.addressLo;
  1601.         fwxUnitInfo.fcAddress.addressHi = pFWXDriverData->fcAddress.addressHi;
  1602.         fwxUnitInfo.fcAddress.addressLo = pFWXDriverData->fcAddress.addressLo;
  1603.  
  1604.         // Create the leaf.
  1605.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1606.                                       &csrROMEntryID,
  1607.                                       kLeafCSRROMEntryType,
  1608.                                       kCSRUnitDependentInfoKey,
  1609.                                       (Ptr) &fwxUnitInfo,
  1610.                                       sizeof (FWXUnitInfo));
  1611.     }
  1612.  
  1613.     // Instantiate CSR ROM.
  1614.     if (status == noErr)
  1615.         status = FWCSRROMInstantiate (pFWXDriverData->fwPDriverID);
  1616.  
  1617.     // Clean up.
  1618.     if (csrROMRootEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1619.         FWCSRROMDisposeEntryID (csrROMRootEntryID);
  1620.  
  1621.     if (csrROMEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1622.         FWCSRROMDisposeEntryID (csrROMEntryID);
  1623.  
  1624.     // Return unit directory ID.
  1625.     if (status == noErr)
  1626.         *pFWPDriverCSRROMUnitDirID = csrROMUnitDirEntryID;
  1627.     else
  1628.         *pFWPDriverCSRROMUnitDirID = kInvalidCSRROMEntryID;
  1629.  
  1630.     return (status);
  1631. }
  1632.  
  1633.  
  1634. ////////////////////////////////////////////////////////////////////////////////
  1635. //
  1636. //    FWXTerminate
  1637. //
  1638. //    This routine terminates the FireWire File Exchange driver.  It
  1639. //    deallocates a private data record and unregisters with the FireWire family.
  1640. //zzz need to do more deallocation:
  1641. //        xmit and receive buffers
  1642. //        CSR ROM unit dir entry
  1643. //        
  1644. //
  1645.  
  1646. static OSStatus    FWXTerminate(
  1647.     FWXTerminateParamsPtr        pFWXTerminateParams)
  1648. {
  1649.     FWXDriverDataPtr            pFWXDriverData;
  1650.     OSStatus                    status = noErr;
  1651.  
  1652. //    FWDebugStr("\pfwix driver terminate");
  1653.     // Get driver data from params.
  1654.     pFWXDriverData = (FWXDriverDataPtr)
  1655.         pFWXTerminateParams->fwxInterfaceParams.pDriverSpecificData;
  1656.  
  1657.     // Deallocate our driver data.
  1658.     if (pFWXDriverData != nil) {
  1659.  
  1660.         if (pFWXDriverData->unitCSRROMEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1661.             FWCSRROMDisposeEntryID (pFWXDriverData->unitCSRROMEntryID);
  1662.  
  1663.         if (pFWXDriverData->controlBuffer != nil)
  1664.             PoolDeallocate((Ptr) pFWXDriverData->controlBuffer);
  1665.         
  1666.         if (pFWXDriverData->fcBuffer != nil)
  1667.             PoolDeallocate((Ptr) pFWXDriverData->fcBuffer);
  1668.         
  1669.         // Unregister with FireWire family.
  1670.         FWUnregisterProtocolDriver(pFWXDriverData->fwPDriverID);
  1671.  
  1672.         // Deallocate our driver data.
  1673.         PoolDeallocate((Ptr) pFWXDriverData);
  1674.     }
  1675.     
  1676.     return status;
  1677. }
  1678.  
  1679. ////////////////////////////////////////////////////////////////////////////////
  1680. //
  1681. //    FWXOpenNode
  1682. //
  1683. //    This routine opens a connections to a remote FWiX node. Allocate a bunch
  1684. //    of buffers and get the remote node's info. Have to send the node our data
  1685. //    address space for him. Use the flow control asynch object and buffers to
  1686. //    handle this. Why? Its there and the right size.
  1687. //
  1688.  
  1689. static OSStatus FWXOpenNode(
  1690.     FWXOpenNodeParamsPtr        pFWXInitializeParams)
  1691. {
  1692.     FWXDriverDataPtr            pFWXDriverData;
  1693.     FWXNodeDataPtr                pFWXNodeData = nil;
  1694.     CSRROMEntryIterator            csrROMIterator = kInvalidCSRROMIterator;
  1695.     CSRROMSearchCriteria        searchCriteria;
  1696.     CSRROMEntryID                unitCSRROMEntryID,
  1697.                                 unitInfoCSRROMEntryID = kInvalidCSRROMEntryID;
  1698.     UInt32                        unitInfoSize;
  1699.     FWCommandObjectID            asynchCommandObjectID;
  1700.     Boolean                        done;
  1701.     OSStatus                    status = noErr;
  1702.  
  1703. //    FWDebugStr("\pFWXOpenNode");
  1704.     // Get our driver data.
  1705.     pFWXDriverData = (FWXDriverDataPtr) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData;
  1706.  
  1707.     // Allocate a node data record
  1708.     pFWXNodeData = (FWXNodeDataPtr) PoolAllocateResident (sizeof (FWXNodeData), true);
  1709.     if (pFWXNodeData != nil)
  1710.     {
  1711.         pFWXNodeData->fwUnitID =
  1712.             (FWUnitID) pFWXInitializeParams->fwxNodeRegistrationReference;
  1713.         pFWXNodeData->pFWXDriverData = pFWXDriverData;
  1714.     }
  1715.     else
  1716.         status = memFullErr;
  1717.     
  1718.     // Allocate a flow control send buffer
  1719.     if (status == noErr)
  1720.     {        
  1721.         pFWXNodeData->fcSendBuffer = (SInt32 *) PoolAllocateResident(kFlowControlSize, false);
  1722.         if (pFWXNodeData->fcSendBuffer == nil)
  1723.             status = memFullErr;
  1724.     }
  1725.  
  1726.     // Allocate a flow control reply buffer
  1727.     if (status == noErr)
  1728.     {        
  1729.         pFWXNodeData->fcReplyBuffer = (SInt32 *) PoolAllocateResident(kFlowControlSize, false);
  1730.         if (pFWXNodeData->fcReplyBuffer == nil)
  1731.         status = memFullErr;
  1732.     }
  1733.     
  1734.     // Allocate a data done buffer
  1735.     if (status == noErr)
  1736.     {        
  1737.         pFWXNodeData->dataDoneBuffer = (SInt32 *) PoolAllocateResident(kDataDoneBufSize, false);
  1738.         if (pFWXNodeData->dataDoneBuffer == nil)
  1739.         status = memFullErr;
  1740.     }
  1741.  
  1742.     // Allocate a data buffer and get address space, have to send this to the
  1743.     // node after the rest of the allocations
  1744.     if (status == noErr)
  1745.     {        
  1746.         pFWXNodeData->dataBuffer = PoolAllocateResident(kFWDataBufferSize, false);
  1747.         if (pFWXNodeData->dataBuffer != nil)
  1748.         {
  1749.             // Get address space for data buffer: allow write, notify is handled with data done message
  1750.             status = FWAllocateAddressSpace (&pFWXNodeData->localDataAddressSpaceID,
  1751.                                               (FWReferenceID) pFWXDriverData->fwPDriverID,
  1752.                                               &pFWXNodeData->localDataAddress,
  1753.                                               kFWDataBufferSize,
  1754.                                               pFWXNodeData->dataBuffer,
  1755.                                              kFWAddressWriteEnable,
  1756.                                              (Ptr) pFWXDriverData);
  1757.         }
  1758.         else
  1759.             status = memFullErr;
  1760.     }
  1761.  
  1762.     // Add node data record to driver's list.
  1763.     if (status == noErr)
  1764.     {
  1765.         if (pFWXDriverData->fwxNodeDataList != nil)
  1766.             pFWXDriverData->fwxNodeDataList->pPrevFWXNodeData = pFWXNodeData;
  1767.  
  1768.         pFWXNodeData->pPrevFWXNodeData = nil;
  1769.         pFWXNodeData->pNextFWXNodeData = pFWXDriverData->fwxNodeDataList;
  1770.  
  1771.         pFWXDriverData->fwxNodeDataList = pFWXNodeData;
  1772.     }
  1773.  
  1774.     // Get node's device ID.
  1775.     if (status == noErr)
  1776.     {
  1777.         status = FWGetFWDeviceIDFromFWReferenceID ((FWReferenceID) pFWXNodeData->fwUnitID,
  1778.                                                    &(pFWXNodeData->fwDeviceID));
  1779.     }
  1780.  
  1781.     // Get node's unit dependent information.
  1782.     if (status == noErr)
  1783.     {
  1784.         // Get unit CSR ROM entry ID.
  1785.         status = FWGetUnitCSRROMEntryID ((FWReferenceID) pFWXNodeData->fwUnitID,
  1786.                                          &unitCSRROMEntryID);
  1787.  
  1788.         // Create a CSR ROM search iterator.
  1789.         if (status == noErr) {
  1790.             status = FWCSRROMCreateIterator (&csrROMIterator,
  1791.                                              (FWReferenceID) pFWXNodeData->fwUnitID);
  1792.         }
  1793.  
  1794.         // Set iterator to start searching at our unit directory.
  1795.         if (status == noErr) {
  1796.             status = FWCSRROMSetIterator (csrROMIterator,
  1797.                                           unitCSRROMEntryID,
  1798.                                           kIterateDescendants);
  1799.         }
  1800.  
  1801.         // Search for unit dependent info leaf.
  1802.         if (status == noErr) {
  1803.             searchCriteria.csrROMSearchType = kCSRROMSearchForKey;
  1804.             searchCriteria.keyType = kCSRLeafKeyTypeBit;
  1805.             searchCriteria.keyHi = kCSRUnitDependentInfoKeyHiBit;
  1806.             searchCriteria.keyLo = kCSRUnitDependentInfoKeyLoBit;
  1807.             unitInfoSize = sizeof (FWXUnitInfo);
  1808.             status = FWCSRROMEntrySearch (csrROMIterator,
  1809.                                           kIterateContinue,
  1810.                                           &unitInfoCSRROMEntryID,
  1811.                                           &done,
  1812.                                           &searchCriteria,
  1813.                                           (Ptr) &(pFWXNodeData->fwxUnitInfo),
  1814.                                           &unitInfoSize);
  1815.         }
  1816.  
  1817.         // Clean up.
  1818.         if (csrROMIterator != (CSRROMEntryIterator) kInvalidCSRROMIterator)
  1819.             FWCSRROMDisposeIterator (csrROMIterator);
  1820.         if (unitInfoCSRROMEntryID != (CSRROMEntryIterator) kInvalidCSRROMEntryID)
  1821.             FWCSRROMDisposeEntryID (unitInfoCSRROMEntryID);
  1822.     }
  1823.  
  1824.     // Allocate FireWire command object for sending asynchronous write packets.
  1825.     if (status == noErr)
  1826.     {
  1827.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1828.         if (status == noErr)
  1829.         {
  1830.             pFWXNodeData->writeAsynchCommandObjectID = asynchCommandObjectID;
  1831.             FWSetFWCommandParams(asynchCommandObjectID,
  1832.                                  (FWReferenceID) pFWXNodeData->fwUnitID,
  1833.                                  0,
  1834.                                  FWXWriteCompletion,
  1835.                                  (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1836.             FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1837.         }
  1838.     }
  1839.  
  1840. #ifdef FireBug
  1841.     FireBugPrep ((FWReferenceID) pFWXNodeData->fwUnitID);
  1842.     sprintf (fireBug, "FWiX FireBug service ready on %s", "(unknown)");    // could add some kind of ID
  1843.     FireBugMsg (fireBug);
  1844. #endif
  1845.  
  1846.     // Allocate FireWire command object for sending flow control packets.
  1847.     if (status == noErr)
  1848.     {
  1849.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1850.         if (status == noErr)
  1851.         {
  1852.             pFWXNodeData->fcSendCommandObjectID = asynchCommandObjectID;
  1853.             FWSetFWCommandParams (asynchCommandObjectID,
  1854.                              (FWReferenceID) pFWXNodeData->fwUnitID,
  1855.                              0,
  1856.                 FlowControlComplete,
  1857.                 (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1858.         FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1859.     }
  1860.     }
  1861.  
  1862.     // Allocate FireWire command object for replying with flow control packets.
  1863.     if (status == noErr)
  1864.     {
  1865.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1866.         if (status == noErr)
  1867.         {
  1868.             pFWXNodeData->fcReplyCommandObjectID = asynchCommandObjectID;
  1869.             FWSetFWCommandParams(asynchCommandObjectID,
  1870.                 (FWReferenceID) pFWXNodeData->fwUnitID,
  1871.                 0,
  1872.                 FlowControlReplyComplete,
  1873.                 (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1874.             FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1875.         }
  1876.     }
  1877.  
  1878.     // setup IO queues
  1879.     if (status == noErr)
  1880.         status = SetupIOQueues(pFWXNodeData);
  1881.  
  1882.     if (status == noErr)
  1883.         FWSetMaxPayloadSize((FWReferenceID) pFWXNodeData->fwUnitID, kFWPacketSize);
  1884.  
  1885.     // Open a connection to the unit.
  1886.     if (status == noErr) {
  1887.         status = FWAddUnitConnection
  1888.                     (pFWXNodeData->fwUnitID, (FWReferenceID) pFWXDriverData->fwPDriverID);
  1889.         if (status == noErr)
  1890.             pFWXNodeData->unitConnectionAdded = true;
  1891.     }
  1892.  
  1893.     // Init control packets to some safe value, this will enable flow control to start
  1894.     if (status == noErr)
  1895.     {
  1896.         pFWXNodeData->controlPbAvail = 5;
  1897.     }
  1898.  
  1899.     // Send the data address space to the remote node using the flow control request packet
  1900.     // JKL *** can this fail, retry?
  1901.     if (status == noErr)
  1902.     {
  1903.         pFWXNodeData->fcSendCommandObjectInUse = true;
  1904.         pFWXNodeData->fcSendBuffer[0] = kAddressInfoRequest;
  1905.         pFWXNodeData->fcSendBuffer[1] = pFWXNodeData->localDataAddress.addressHi;
  1906.         pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->localDataAddress.addressLo;
  1907.         FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1908.         FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1909.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1910.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1911.                                         (Ptr) pFWXNodeData->fcSendBuffer,
  1912.                                         kFlowControlSize);
  1913.         status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1914.         if (status != noErr)
  1915.             pFWXNodeData->fcSendCommandObjectInUse = false;
  1916.     }
  1917.     
  1918.     // Clean up on error.
  1919.     if (status != noErr) {
  1920.         if (pFWXNodeData != nil)
  1921.         {
  1922.             sprintf(debugStr,"Closing node from OpenNode, error: %ld", status);
  1923.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1924.             FWXCloseNode (pFWXNodeData);
  1925.         }
  1926.     }
  1927.  
  1928.     // Return results.
  1929.     if (status == noErr)
  1930.         pFWXInitializeParams->fwxInterfaceParams.pNodeSpecificData = (Ptr) pFWXNodeData;
  1931.     else
  1932.         pFWXInitializeParams->fwxInterfaceParams.pNodeSpecificData = nil;
  1933.  
  1934.     return status;
  1935. }
  1936.  
  1937. ////////////////////////////////////////////////////////////////////////////////
  1938. //
  1939. //    FWXCloseNode
  1940. //
  1941. //    This routine closes a connections to a remote FWiX node.
  1942. //
  1943. static OSStatus FWXCloseNode(
  1944.     FWXNodeDataPtr                pFWXNodeData)
  1945. {
  1946.     FWXDriverDataPtr            pFWXDriverData;
  1947.     FWXNodeDataPtr                pPrevFWXNodeData,
  1948.                                 pNextFWXNodeData;
  1949.     volatile Boolean            *pFWCommandObjectInUse;
  1950.     IOParamPtr                    pIOPB;
  1951.     AbsoluteTime                timeRemaining;
  1952.     OSStatus                    status = noErr;
  1953.  
  1954. //    FWDebugStr("\pFWXCloseNode");
  1955.     if (pFWXNodeData != nil) {
  1956.         // Get our driver data.
  1957.         pFWXDriverData = (FWXDriverDataPtr) pFWXNodeData->pFWXDriverData;
  1958.  
  1959.         // Set node closed.
  1960.         pFWXNodeData->closed = true;
  1961.         CancelTimer(pFWXNodeData->fcTimerID, &timeRemaining);
  1962.  
  1963.         // Wait for all command objects to be no longer in use.
  1964.         pFWCommandObjectInUse = &(pFWXNodeData->writeAsynchCommandObjectInUse);
  1965.         while (*pFWCommandObjectInUse);
  1966.         pFWCommandObjectInUse = &(pFWXNodeData->fcSendCommandObjectInUse);
  1967.         while (*pFWCommandObjectInUse);
  1968.         pFWCommandObjectInUse = &(pFWXNodeData->fcReplyCommandObjectInUse);
  1969.         while (*pFWCommandObjectInUse);
  1970.  
  1971.         // Deallocate queues, write queue
  1972.         if (pFWXNodeData->pWriteQHdr != nil) {
  1973.             pIOPB = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1974.             while (pIOPB != nil) {
  1975.                 PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &pIOPB);
  1976.                 pIOPB->ioActCount = 0;
  1977.                 FWXCommandIsComplete(pIOPB, noErr);
  1978.                 pIOPB = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1979.             }
  1980.             PBQueueDelete(pFWXNodeData->pWriteQHdr);
  1981.         }
  1982.         
  1983.         if (pFWXNodeData->pReadControlQHdr != nil) {
  1984.             pIOPB = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  1985.             while (pIOPB != nil) {
  1986.                 PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1987.                 pIOPB->ioActCount = 0;
  1988.                 FWXCommandIsComplete(pIOPB, noErr);
  1989.                 pIOPB = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  1990.             }
  1991.             PBQueueDelete(pFWXNodeData->pReadControlQHdr);
  1992.         }
  1993.  
  1994.         if (pFWXNodeData->pReadDataQHdr != nil) {
  1995.             pIOPB = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;
  1996.             while (pIOPB != nil) {
  1997.                 PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1998.                 pIOPB->ioActCount = 0;
  1999.                 FWXCommandIsComplete(pIOPB, noErr);
  2000.                 pIOPB = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;
  2001.             }
  2002.             PBQueueDelete(pFWXNodeData->pReadDataQHdr);
  2003.             pFWXNodeData->dataPbCount = 0;
  2004.             pFWXNodeData->controlPbCount = 0;
  2005.             pFWXNodeData->dataPbAvail = 0;
  2006.             pFWXNodeData->controlPbAvail = 0;
  2007.         }
  2008.  
  2009.         // Deallocate command object for sending asynchronous write packets.
  2010.         if (pFWXNodeData->writeAsynchCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2011.             FWDeallocateFWCommandObject (pFWXNodeData->writeAsynchCommandObjectID);
  2012.  
  2013.         // Deallocate command objects for flow control packets.
  2014.         if (pFWXNodeData->fcSendCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2015.             FWDeallocateFWCommandObject (pFWXNodeData->fcSendCommandObjectID);
  2016.         if (pFWXNodeData->fcReplyCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2017.             FWDeallocateFWCommandObject (pFWXNodeData->fcReplyCommandObjectID);
  2018.  
  2019.         // Remove node data record from driver's list.
  2020.         pPrevFWXNodeData = pFWXNodeData->pPrevFWXNodeData;
  2021.         pNextFWXNodeData = pFWXNodeData->pNextFWXNodeData;
  2022.  
  2023.         // Remove our connection to unit.
  2024.         if (pFWXNodeData->unitConnectionAdded) {
  2025.             FWRemoveUnitConnection (pFWXNodeData->fwUnitID,
  2026.                                     (FWReferenceID) pFWXDriverData->fwPDriverID);
  2027.         }
  2028.  
  2029.         if (pPrevFWXNodeData != nil) {
  2030.             pPrevFWXNodeData->pNextFWXNodeData = pNextFWXNodeData;
  2031.         } else {
  2032.             if (pFWXDriverData->fwxNodeDataList == pFWXNodeData)
  2033.                 pFWXDriverData->fwxNodeDataList = pNextFWXNodeData;
  2034.         }
  2035.  
  2036.         if (pNextFWXNodeData != nil)
  2037.             pNextFWXNodeData->pPrevFWXNodeData = pPrevFWXNodeData;
  2038.  
  2039.         // Deallocate buffers
  2040.         if (pFWXNodeData->fcSendBuffer != nil)
  2041.             PoolDeallocate ((Ptr) pFWXNodeData->fcSendBuffer);
  2042.         if (pFWXNodeData->fcReplyBuffer != nil)
  2043.             PoolDeallocate ((Ptr) pFWXNodeData->fcReplyBuffer);
  2044.         if (pFWXNodeData->dataDoneBuffer != nil)
  2045.             PoolDeallocate ((Ptr) pFWXNodeData->dataDoneBuffer);
  2046.         if (pFWXNodeData->dataBuffer != nil)
  2047.             PoolDeallocate((Ptr) pFWXNodeData->dataBuffer);
  2048.  
  2049.         // Deallocate address space
  2050.         FWDeallocateAddressSpace(pFWXNodeData->localDataAddressSpaceID);
  2051.  
  2052.         // Deallocate node data record.
  2053.         PoolDeallocate ((Ptr) pFWXNodeData);
  2054.     }
  2055.  
  2056.     return status;
  2057. }
  2058.  
  2059. //////////////////////////////////////////////////////////////////////////////
  2060. //
  2061. //    SetupIOQueues
  2062. //
  2063. //    Setup the queueus. Create and initialize.
  2064. //
  2065. static OSStatus SetupIOQueues(
  2066.     FWXNodeDataPtr        pFWXNodeData)
  2067. {
  2068.     OSStatus            status = noErr;
  2069.     
  2070.     status = PBQueueCreate(& pFWXNodeData->pReadDataQHdr);
  2071.     if (status == noErr)
  2072.         PBQueueInit(pFWXNodeData->pReadDataQHdr);
  2073.     else
  2074.         return status;
  2075.         
  2076.     status = PBQueueCreate(& pFWXNodeData->pReadControlQHdr);
  2077.     if (status == noErr)
  2078.         PBQueueInit(pFWXNodeData->pReadControlQHdr);
  2079.     else
  2080.         return status;
  2081.         
  2082.         status = PBQueueCreate(& pFWXNodeData->pWriteQHdr);
  2083.         if (status == noErr)
  2084.             PBQueueInit(pFWXNodeData->pWriteQHdr);
  2085.     
  2086.     return status;    
  2087. }    
  2088.  
  2089. //////////////////////////////////////////////////////////////////////////////
  2090. //
  2091. //    FWXGetNodeDataFromNodeID
  2092. //
  2093. //    Return the FWX node data record that matches the given node ID.
  2094. //
  2095. static OSStatus FWXGetNodeDataFromNodeID (
  2096.     FWXDriverDataPtr            pFWXDriverData,
  2097.     UInt32                        generation,
  2098.     UInt32                        nodeID,
  2099.     FWXNodeDataPtr                *ppFWXNodeData)
  2100. {
  2101.     FWXNodeDataPtr                pFWXNodeData;
  2102.     FWDeviceID                    fwDeviceID;
  2103.     Boolean                        found;
  2104.     OSStatus                    status = noErr;
  2105.  
  2106.     // Get FireWire device ID for nodeID.
  2107.     status = FWFindFWDeviceFromNodeID (pFWXDriverData->fwPDriverID,
  2108.                                        generation,
  2109.                                        nodeID,
  2110.                                        &fwDeviceID);
  2111.  
  2112.     // Search node data list for node with matching deviceID.
  2113.     if (status == noErr) {
  2114.         pFWXNodeData = pFWXDriverData->fwxNodeDataList;
  2115.         found = false;
  2116.         while ((pFWXNodeData != nil) && (!found))
  2117.         {
  2118.             if ((pFWXNodeData->fwDeviceID == fwDeviceID) && (!(pFWXNodeData->closed)))
  2119.                 found = true;
  2120.             else
  2121.                 pFWXNodeData = pFWXNodeData->pNextFWXNodeData;
  2122.         }
  2123.     }
  2124.  
  2125.     // Return results.
  2126.     if (status == noErr) {
  2127.         if (found) {
  2128.             *ppFWXNodeData = pFWXNodeData;
  2129.         } else {
  2130.             *ppFWXNodeData = nil;
  2131.             status = notFoundErr;
  2132.         }
  2133.     } else {
  2134.         *ppFWXNodeData = nil;
  2135.     }
  2136.  
  2137.     return (status);
  2138. }
  2139.